package com.sinaapp.mspring.aop;

import java.lang.reflect.Method;
import java.util.Date;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import com.alibaba.fastjson.JSON;
import com.sinaapp.mspring.annotation.SystemControllerLog;
import com.sinaapp.mspring.annotation.SystemServiceLog;
import com.sinaapp.mspring.model.pojo.SysLog;
import com.sinaapp.mspring.service.SysLogServiceI;


/**
 * 系统日志AOP
 * 
 * @author binchao
 * 2016年3月12日
 */
@Aspect
@Component
public class LogAspect {
	
	private static final Logger logger = LoggerFactory.getLogger(LogAspect.class);
	
	@Autowired
	private SysLogServiceI sysLogService;
	
	/**
	 * controller切点
	 */
	@Pointcut("@annotation(com.sinaapp.mspring.annotation.SystemControllerLog)")
	public void controllerAspect(){}
	
	@Pointcut("@annotation(com.sinaapp.mspring.annotation.SystemServiceLog)")
	public void serviceAspect(){}
	
	@Before("controllerAspect()")
	public void doBefore(JoinPoint joinPoint) {
		
		HttpServletRequest request = ((ServletRequestAttributes)RequestContextHolder
				.getRequestAttributes()).getRequest();
		HttpSession session = request.getSession();
		
		//当前用户
		String userName = "游客";
		//用户IP
		String ip = request.getRemoteAddr();
		//访问的类
		String className = joinPoint.getTarget().getClass().getName();
		//访问的方法
		String method = joinPoint.getSignature().getName() + "()";
		
		try {
			//访问的方法描述
			String methodDescription = getControllerMethodDescription(joinPoint);
			logger.debug("==========前置通知开始==========");
			logger.debug("请求方法：" + className + "." +  method);
			logger.debug("方法描述：" + methodDescription);
			logger.debug("请求人：" + userName);
			logger.debug("请求IP：" + ip);
			/* =========数据库日志=========*/
			SysLog log = new SysLog();
			log.setMethod(className + "." + method);
			log.setIp(ip);
			log.setCreatedate(new Date());
			log.setDescription(methodDescription);
			log.setType(0);
			log.setUserid(1);
			sysLogService.insert(log);
		} catch (Exception e) {
			logger.error("===前置通知异常===");
			logger.error("异常信息：{}", e.getMessage());
		}
	}
	

	/**
	 * 异常通知，用于拦截service层异常记录日志
	 * 
	 * @param joinPoint
	 * @param e
	 */
	@AfterThrowing(pointcut = "serviceAspect()", throwing = "e")
	public void doAfterThrowing(JoinPoint joinPoint, Throwable e) {
		
		HttpServletRequest request = ((ServletRequestAttributes)RequestContextHolder
				.getRequestAttributes()).getRequest();
		HttpSession session = request.getSession();
		
		//当前用户
		String userName = "测试";
		//用户IP
		String ip = request.getRemoteAddr();
		//访问的类
		String className = joinPoint.getTarget().getClass().getName();
		//访问的方法
		String method = joinPoint.getSignature().getName() + "()";
		
		//获取用户请求方法的参数并序列化为JSON格式字符串    
        String params = "";    
         if (joinPoint.getArgs() !=  null && joinPoint.getArgs().length > 0) {    
             for ( int i = 0; i < joinPoint.getArgs().length; i++) {    
                params += JSON.toJSONString(joinPoint.getArgs()[i]) + ";";    
            }    
        }    
         try {    
        	//访问的方法描述
     		String methodDescription = getServiceMethodDescription(joinPoint);
            /*========控制台输出=========*/    
        	logger.info("=====异常通知开始=====");    
        	logger.info("异常代码:" + e.getClass().getName());    
        	logger.info("异常信息:" + e.getMessage());    
        	logger.info("异常方法:" + className + "." + method);    
        	logger.info("方法描述:" + methodDescription);    
        	logger.info("请求人:" + userName);    
        	logger.info("请求IP:" + ip);    
        	logger.info("请求参数:" + params);    
               /*==========数据库日志=========*/    
            SysLog log = new SysLog();
            log.setDescription(methodDescription);
            log.setExceptioncode(e.getClass().getName());
            log.setType(1);    
            log.setExceptiondetail(e.getMessage()); 
            log.setMethod(className + "." + method);    
            log.setParams(params);    
            log.setIp(ip);
            log.setUserid(1);
            //保存数据库    
            sysLogService.insert(log);
            logger.info("=====异常通知结束=====");    
        }  catch (Exception ex) {    
            //记录本地异常日志    
            logger.error("==异常通知异常==");    
            logger.error("异常信息:{}", ex.getMessage());    
        }    
         /*==========记录本地异常日志==========*/    
        logger.error("异常方法:{}异常代码:{}异常信息:{}参数:{}", className + "." + joinPoint.getSignature().getName(), e.getClass().getName(), e.getMessage(), params);    
	}
	
	/**
	 * 获取注解中对controller的描述
	 * 
	 * @param joinPoint
	 * @return
	 * @throws Exception
	 */
	private String getControllerMethodDescription(JoinPoint joinPoint) throws Exception {
		String targetName = joinPoint.getTarget().getClass().getName();    
        String methodName = joinPoint.getSignature().getName();    
        Object[] arguments = joinPoint.getArgs();    
        Class targetClass = Class.forName(targetName);    
        Method[] methods = targetClass.getMethods();    
        String description = "";    
         for (Method method : methods) {    
             if (method.getName().equals(methodName)) {    
                Class[] clazzs = method.getParameterTypes();    
                 if (clazzs.length == arguments.length) {    
                    description = method.getAnnotation(SystemControllerLog.class).description();    
                     break;    
                }    
            }    
        }    
        return description;    
	}
	
	/**
	 * 获取注解中对service的描述
	 * 
	 * @param joinPoint
	 * @return
	 * @throws Exception
	 */
	private String getServiceMethodDescription(JoinPoint joinPoint) throws Exception {
		String targetName = joinPoint.getTarget().getClass().getName();    
        String methodName = joinPoint.getSignature().getName();    
        Object[] arguments = joinPoint.getArgs();    
        Class targetClass = Class.forName(targetName);    
        Method[] methods = targetClass.getMethods();    
        String description = "";    
         for (Method method : methods) {    
             if (method.getName().equals(methodName)) {    
                Class[] clazzs = method.getParameterTypes();    
                 if (clazzs.length == arguments.length) {    
                    description = method.getAnnotation(SystemServiceLog.class).description();    
                     break;    
                }    
            }    
        }    
         return description; 
	}
	
}
